using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.ComponentModel;
using MimeCloud.AssetManagement.Business.Interface;
using MimeCloud.AssetManagement.Editor.AssetCreation.Repository;
using MimeCloud.AssetManagement.ProviderServices;
using MimeCloud.AssetManagement.ProviderServices.Repository;
using MimeCloud.AssetManagement.Editor.AssetCreation;
using MimeCloud.Foundations.ErrorLogging;

namespace MimeCloud.AssetManagement.Editor.Saving
{
    /// <summary>
    /// Handles the saving to data stores in the event that the data store and the file stores are separate. Uses the data provider to manage data stores, and the repository manager provider for file stores
    /// </summary>
    public class DisparateDataSaveManager : SaveManagerBase
    {
       
        protected override AssetSaveResult ExecuteSaveTasks (AssetSaveArguments args, DoWorkEventArgs e)
        {
            AssetSaveResult result = new AssetSaveResult();
            int assetsDone = args.AssetsToSave.Count;
            e.Result = "";

            var failedAssets = new List<FailedAssetSave>();
            var successfulAssets = new List<IAsset>();

            //perform operation for each asset
            foreach (IAsset asset in args.AssetsToSave)
            {
                //count progress
                assetsDone--;

                //check for cancellation per asset, don't cancel an asset without the rest of linked content
                if (saveWorker.CancellationPending)
                {
                    e.Cancel = true;
                    goto Logoff;
                    break;
                }

                //todo: allow plugin to alter file path of each asset content, or store metadata on the overall asset

                //todo: type generation (image cropping / video encoding)
                
                //iterate through each assetcontent and perform upload
                bool contentUploadFailure = false;
                foreach (IAssetContent content in asset.AssetContentList)
                {
                    //only upload the file if it is stored locally
                    if (LocalRepository.IsAssetContentLocallyStored(content))
                    {
                        //decide repository based on mime type
                        IRepositoryManager repoManager = GetRepositoryManager(content.MimeType._MimeType);

                        bool contentUploadSuccess = false;

                        //set path
                        string fileName = Path.GetFileName(content.AssetPath);
                        content.AssetPath =
                            Path.Combine(Path.Combine(content.MimeType._MimeType, content.AssetContentType.Name),
                                         fileName).Replace('\\','/');

                        try
                        {
                            contentUploadSuccess = repoManager.UploadAssetContentData(content);
                            if (contentUploadSuccess)
                            {
                                //change repository to new repo
                                content.AssetContentRepositoryList.Clear();
                                content.AssetContentRepositoryList.Add(repoManager.DataRepository);
                            }
                        }
                        catch (Exception ex)
                        {
                            ErrorHelper.LogError(new Exception("Could not upload asset content",ex));
                        }
                        if (!contentUploadSuccess)
                            contentUploadFailure = true;
                    }
                }

                //if upload failed, do not save to db, continue to next asset
                if (contentUploadFailure)
                {
                    failedAssets.Add(new FailedAssetSave {FailAsset = asset});
                    continue;
                }

                //save tp database
                AssetManagerConfig.GetAssetWriterProvider().SaveAsset(asset);
                

                successfulAssets.Add(asset);
            }

        Logoff:
            ReportProgress(new AssetSaveProgressReport { Message = "Finished all assets" });

            e.Result = result;
            return result;
        }

        private IRepositoryManager GetRepositoryManager(string mimeType)
        {
            IRepositoryManager result;
            if (
                AssetManagerConfig.Current.CurrentRepositoryDetailCollection.MimeTypeRepositories.AllKeys.Contains(
                    mimeType))
            {
                result =
                    AssetManagerConfig.Current.RepositoryManagers[
                        AssetManagerConfig.Current.CurrentRepositoryDetailCollection.MimeTypeRepositories[mimeType].
                            Value];
            }
            else
                result = AssetManagerConfig.Current.DefaultRepositoryManager;
            result.DataRepository =
                (from repo in AppCommon.Current.AllRepositories where repo.Name == result.RepositoryKey select repo).
                    First();
            result.SaveProgressReporter = ReportProgress;
            return result;
        }

      

        public static class FileNameManager
        {
            public static void AssignUniqueImageFileName(ref IAssetContent assetContent, IsFileNameUnique fileNameUniqueLooker)
            {
                AssignUniqueImageFileName(ref assetContent, 0, fileNameUniqueLooker);
            }

            public delegate bool IsFileNameUnique(IAssetContent assetContent);

            public static void AssignUniqueImageFileName(ref IAssetContent assetContent, int lastTry, IsFileNameUnique fileNameUniqueLooker)
            {
                string originalFileName = assetContent.AssetPath.Clone() as String;
                if (lastTry > 0)
                {
                    //try with new filename
                    //make unique name
                    string fileNameNoExt = Path.GetFileNameWithoutExtension(assetContent.AssetPath);
                    string newfileNameNoExt = String.Concat(fileNameNoExt, "_", lastTry);
                    assetContent.AssetPath = assetContent.AssetPath.Replace(fileNameNoExt, newfileNameNoExt);
                }
                //ImageTypeData lookupFile = file;
                //get number of existing files with this unique name
                bool newNameIsUnique = fileNameUniqueLooker(assetContent);

                //return if filename is unique
                if (newNameIsUnique) return;

                //photo exists, try with new filename
                //log
                ErrorHelper.LogMessage(
                    "File already exists at same name and path. Making unique name for file",
                    "file name tried is: " + assetContent.AssetPath);
                //reset filename to original
                if (lastTry > 0)
                {
                    //revert to orignal filename, but try with new value
                    assetContent.AssetPath = originalFileName;
                }
                //increase number to try for unique name
                lastTry++;
                //try
                AssignUniqueImageFileName(ref assetContent, lastTry, fileNameUniqueLooker);
            }
        }
    }
}
